#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "BF_Defines.h"
#include "HF_Lib.h"
#include "AM_Lib.h"
#include "UT_DM_Defines.h"
#include "CFM_Lib.h"

int GetOffset ( attrDesc *attrs, char *attribute );
int ToOperator ( char *op );
int GetLenght ( char *type );
attrDesc GetAttributeInfo ( attrDesc *attrs, char *attribute );
BOOLEAN IsIndexed ( attrDesc *attrs, char *attribute );
int ToOperator ( char *op );
static char *GetType ( attrDesc *attrs, char *attrName );

/*Η συνάρτηση αυτή καλείται από την yyparse όταν ο χρήστης πληκτρολογήσει μια εντολή SELECT 

 *η οποία να μην είναι τύπου ζεύξης. Σε ό,τι αφορά την υλοποίηση της εντολής αυτής, παρατηρήστε ότι

 *όταν ζητείται να τυπωθούν τα αποτελέσματα στην οθόνη, μπορείτε να εισάγετε τα αποτελέσματα σε μία

 *προσωρινή σχέση, στην συνέχεια να τυπώσετε τα περιεχόμενα της σχέσης αυτής και τέλος να την καταστρέψετε.

 *Επομένως, μπορείτε να χειρισθείτε την περίπτωση που τα αποτελέσματα πρέπει να εισαχθούν σε μία σχέση 

 *ως μια ειδίκευση της περίπτωσης που τα αποτελέσματα πρέπει απλά να τυπωθούν.

 *Καθώς θα σαρώνετε τις εγγραφές για να επιλέξετε αυτές που ικανοποιούν το κριτήριο της επιλογής (αν βέβαια υπάρχει),

 *θα πρέπει ταυτόχρονα να κάνετε και τον περιορισμό πάνω στα γνωρίσματα που τελικά θα υπάρχουν στην απάντηση της ερώτησης.

 *Δεν πρέπει να κάνετε πρώτα την επιλογή των εγγραφών και στην συνέχεια να κάνετε τον περιορισμό πάνω στα γνωρίσματα που

 *υπάρχουν στην εντολή. Αν υπάρχει ευρετήριο πάνω στο όνομα-πεδίου-επιλογής τότε θα πρέπει υποχρεωτικά να το χρησιμοποιήσετε 

 *εφόσον ο τελεστής υποστηρίζεται από τον τύπο του ευρετηρίου. Τέλος, προσοχή θέλει το γεγονός ότι το στοιχείο τιμή (όπως επίσης

 *και το στοιχείο τελεστής) είναι δείκτης σε κείμενο, δηλαδή θα πρέπει εσείς να κάνετε την μετατροπή στον σωστό τύπο.

 * 
 *  argv[0]="select"

 *  argv[1]=όνομα-σχέσης-αποτελέσματος					Προαιρετικό στοιχείο 

 *   argv[2]=πλήθος-γνωρισμάτων-τα-οποία-προβάλλονται	ακέραιος 

 *   argv[3]=όνομα-προβαλλόμενης-σχέσης-1

 *   argv[4]=όνομα-προβαλλόμενου-πεδίου-1

 *   .

 *   .

 *   .

 *   argv[argc-5]=όνομα-προβαλλόμενου-πεδίου-Ν

 *   argv[argc-4]=όνομα-σχέσης-επιλογής					Τα στοιχεία 

 *   argv[argc-3]=όνομα-πεδίου-επιλογής					αυτά 

 *   argv[argc-2]=τελεστής								είναι 

 *   argv[argc-1]=τιμή									προαιρετικά 

 *   argv[argc]=NULL

 */
int DM_select ( int argc, char *argv[] )
{
	char resultTable[MAXNAME], selectedRel[MAXNAME], *record, *newRecord, **createArgs;
	int attributes, relFd, newRelFd, retval, scanFd, i, j, attrStart, error, fileDesc, createArgc;
	BOOLEAN condition;
	relDesc rel, newRel;
	attrDesc *attrs, *newAttrs;

	/* Έλεγχος τον ορισμάτων. */

	if ( SCM_select ( argc, argv ) < 0 )
	{
		return UTE_errno = SCM_SELECT;
	}

	/* Αν έχουμε όνομα σχέσης αποτελέσματος, το αποθηκεύουμε */

	if ( argc % 2 == 1 )
	{
		strcpy ( resultTable, argv[1] );
		strcpy ( selectedRel, argv[3] );
	}
	else
	{
		/* Αλλιώς βάζω ένα προσωρινό όνομα στη σχέση, 
		 *γιατί μόλις την τυπώσω θα την διαγράψω αφού
		 *ο χρήστης δεν την θέλει.
		 */

		strcpy ( resultTable, "iucgsdc" );		
		strcpy ( selectedRel, argv[2] );
	}

	/* Προσκόμηση του αριθμού attributes, η θέση του οποίου εξαρτάται
	 *απο το πρώτο προεραιτικό στοιχείο.
	 */

	if ( argc % 2 == 1 )
	{
		attributes = atoi ( argv[2] );
	}
	else
	{
		attributes = atoi ( argv[1] );
	}
	
	/* Έλεγχος αν έχουμε συνθήκη πάνω σε κάποια απο τα προβαλόμενα attributes. */

	if ( argc == 2 * attributes + 3 )
	{
		condition = FALSE;
	}
	else if ( argc == 2 * attributes + 2 )
	{
		condition = FALSE;
	}
	else
	{
		condition = TRUE;
	}

	/* Προσκόμηση απο τους πίνακες attrCat και relCat πληροφορίες
	 *για το recordSize και το attrLenght τους για να γίνει το σκαναρισμα.
	 */

	if ( ( error = CFM_Lookup ( selectedRel, &rel, &attrs ) ) < 0 )
	{
		return UTE_errno = UTE_SELECT;
	}

	/* Επιλογή της θέσης που ξεκινάνε τα attributes. */

	if ( argc % 2 == 1 )
	{
		attrStart = 4;
	}
	else
	{
		attrStart = 3;
	}

	/*Χτίσιμο των ορισμάτων της UT_create για να δημιουργήσουμε την καινούρια
	 *( προσωρινή ίσως) σχέση αποτελεσμάτων.
	 */

	createArgc = 2 * attributes + 2;
	createArgs = malloc ( sizeof(char) * createArgc );
	for ( i = 0; i <= createArgc; i++ )
		createArgs[i] = malloc ( sizeof(char) * MAXNAME );

	strcpy ( createArgs[0], "create" );
	strcpy ( createArgs[1], resultTable );

	for ( i = 0, j = 2; i < attributes; i++, attrStart += 2, j += 2 )
	{
		int l;
		attrDesc attibuteInfo;

		/* Εύρεση των attribute info για τα επιλεγμένα attributes */

		attibuteInfo = GetAttributeInfo ( attrs, argv[attrStart] );

		strcpy ( createArgs[j], argv[attrStart] );
		
		if ( attibuteInfo.attrtype == 'i' || attibuteInfo.attrtype == 'f' )
		{
			sprintf ( createArgs[j + 1], "'%c'", attibuteInfo.attrtype );
		}
		else
		{
			sprintf ( createArgs[j + 1], "'%c%d'", attibuteInfo.attrtype, attibuteInfo.attrlength );
		}
	}

	strcpy ( createArgs[createArgc], "NULL" );

	/* Δημιουργία της καινούριας ( ίσως προσωρινής ) σχέσης. */

	if ( UT_create ( createArgc, createArgs ) < 0 )
	{
		return UTE_errno = UTE_SELECT;
	}

	/* Άνοιγμα του αρχείου για να βάλουμε τις εγγραφές αποτελέσματα. */
		
	if ( ( newRelFd = HF_OpenFile ( resultTable ) ) < 0 )
	{
		HF_PrintError ( "Error in select" );
		return UTE_errno = UTE_HF_ERROR;		
	}

	record = malloc ( sizeof(char) * rel.relwidth );
	
	/* προσκόμηση της πληροφορίες απο τους καταλόγους 
	 *για τον ( ίσως ) προσωρινό πίνακα που φτιάξαμε.
	 */

	if ( CFM_Lookup ( resultTable, &newRel, &newAttrs ) < 0 )
	{
		return UTE_errno = UTE_JOIN;
	}

	newRecord = malloc ( sizeof(char) * newRel.relwidth );

	/* Άνοιγμα του αρχείου της προβαλλόμενης σχέσης. */

	if ( ( relFd = HF_OpenFile ( selectedRel ) ) < 0 )
    {
		HF_PrintError ( "Error in select " );			
		return UTE_errno =  UTE_HF_ERROR;
    }

	/* Αν δεν έχω συνθήκη, ή αν έχω και το πεδίο επιλογής δεν ειναι ευρετηριασμένο. */

	if ( condition == FALSE || ( condition == TRUE && IsIndexed ( attrs, argv[argc - 3] ) == FALSE ) )
	{

		if ( condition == FALSE )
		{
			/*Αν δεν έχω συνθήκη, προσκόμηση όλων των εγγραφών του πίνακα. */

			if ( (scanFd = HF_OpenFileScan ( relFd, rel.relwidth, 'i', 4, 0, EQUAL, NULL ) ) < 0 )

			{
				HF_PrintError ( "Error in opening scan" );
				return UTE_errno = UTE_HF_ERROR;
			}
		}
		else
		{
			/*Αλλιως ανοίγω scan με ορισμα την συνθήκη. */

			int op = ToOperator ( argv[argc - 2] );
			attrDesc selectedAttr = GetAttributeInfo ( attrs, argv[argc - 3] );

			if ( ( scanFd = HF_OpenFileScan ( relFd, rel.relwidth, selectedAttr.attrtype , selectedAttr.attrlength , selectedAttr.offset, op, argv[argc - 1] ) ) < 0 )
			{
				HF_PrintError ( "Error in opening scan" );
				return UTE_errno = UTE_HF_ERROR;
			}
		}

		if ( scanFd < 0 )
		{
			HF_PrintError ( "Error in select" );
			return UTE_errno = UTE_HF_ERROR;
		}

		/* Για κάθε εγγραφή που επιστρέφει το scan πρέπει να επιλέγω τα attributes
		 *που έχει ζητήσει ο χρήστης. 
		 */

		while ( ( retval = HF_FindNextRec ( scanFd, record) ) != HFE_EOF )
		{
			if ( retval < 0 )
			{
				HF_PrintError ( "Error in select" );
				return UTE_errno = UTE_HF_ERROR;			
			}

			/* Επιλογή των attributes που έχει ζητήσει ο χρήστης. */

			for ( i = 0; i < newRel.attrcnt; i++ )
			{
				int offset = GetOffset ( attrs, newAttrs[i].attrname );
				memcpy ( &newRecord[newAttrs[i].offset], &record[offset], GetAttributeInfo ( attrs, newAttrs[i].attrname ).attrlength );
			}

			/* Εισαγωγή της εγγραφής που χτίσαμε στην καινούρια σχέση. */

			if ( HF_InsertRec ( newRelFd, newRecord, newRel.relwidth ) < 0 )
			{			
				HF_PrintError ( "Error in select" );
				return UTE_errno = UTE_HF_ERROR;			
			}
		}

		if ( HF_CloseFileScan ( scanFd ) < 0 )
		{
				HF_PrintError ( "Error in select" );
				return UTE_errno = UTE_HF_ERROR;						
		}
	}
	else if ( IsIndexed ( attrs, argv[argc - 3] ) && condition == TRUE )
	{
		/* Αλλιώς αν είναι ευρετηριασμένο το πεδίο επιλογής. */

		int indexDesc, scanDesc, recId, fileDesc;
		int op = ToOperator ( argv[argc - 2] );
		attrDesc selectedAttr = GetAttributeInfo ( attrs, argv[argc - 3] );

		/* Άνοιγμα του ευρετηρίου. */

		if ( ( indexDesc = AM_OpenIndex ( selectedRel, selectedAttr.indexno) < 0 ) )
		{
			AM_PrintError ( "Error oin select" );
			return UTE_errno = UTE_INDEX;
		}

		/* Έναρξη σάρωσης στο ευρετήριο. */

		if ( scanDesc = AM_OpenIndexScan ( indexDesc, selectedAttr.attrtype, selectedAttr.attrlength, op, argv[argc - 1] ) < 0 )
		{
			AM_PrintError ( "Error oin select" );
			return UTE_errno = UTE_INDEX;		
		}

		/* Ανοιγμα του HF αρχείου. */

		if ( ( fileDesc = HF_OpenFile ( selectedRel ) ) < 0 )
		{
				HF_PrintError ( "Error in select" );
				return UTE_errno = UTE_HF_ERROR;					
		}

		/* Προσκόμοιση των εγγραφών που ικανοποιούν την συνθήκη. */

		while ( ( recId = AM_FindNextEntry ( scanDesc ) ) != AME_EOF )
		{
			if ( recId < 0 )
			{
				AM_PrintError ( "Error in select" );
				return UTE_errno = UTE_INDEX;				
			}


			if ( HF_GetThisRec ( fileDesc, recId, record, rel.relwidth ) < 0 )
			{
				continue;
			}

			/* Επιλογή των attributes που έχει ζητήσει ο χρήστης. */

			for ( i = 0; i < newRel.attrcnt; i++ )
			{
				int offset = GetOffset ( attrs, newAttrs[i].attrname );
				memcpy ( &newRecord[newAttrs[i].offset], &record[offset], newAttrs[i].attrlength );
			}

			/* Εισαγωγή της εγγραφής που χτίσαμε στην καινούρια σχέση. */

			if ( HF_InsertRec ( newRelFd, newRecord, newRel.relwidth ) < 0 )
			{			
				HF_PrintError ( "Error in select" );
				return UTE_errno = UTE_HF_ERROR;			
			}

		}

		if ( AM_CloseIndex ( scanDesc )< 0 )
		{
				AM_PrintError ( "Error in select" );
				return UTE_errno = UTE_INDEX;		
		}
	}

	/* Κλείσιμο του αρχείου της προβαλλόμενης σχέσης. */

	if ( HF_CloseFile ( relFd )  < 0 )
    {
		HF_PrintError ( "Error in select " );			
		return UTE_errno =  UTE_HF_ERROR;
    }

	/* Κλείσιμο του αρχείου της σχέσης αποτελέσματος. */

	if ( HF_CloseFile ( newRelFd ) < 0 )
	{
		HF_PrintError ( "Error in select" );
		return UTE_errno = UTE_HF_ERROR;	
	}


	/* Αν ο χρήστης δεν ζήτησε αποθήκευση της σχέσης αποτελέσματος, τη διαγράφω. */

	if ( argc % 2 == 0 )
	{
		char arguments[3][MAXNAME];

		/* Εκτύπωση του αποτελέσματος. */

		strcpy ( arguments[0], "delete" );
		strcpy ( arguments[1], resultTable );
		strcpy ( arguments[2], "NULL" );

		if ( UT_print ( resultTable ) < 0 )
		{
			return UTE_errno = UTE_SELECT;
		}

		if ( UT_destroy ( 3, arguments ) < 0 )
		{
			return UTE_errno = UTE_JOIN;
		}

		if ( HF_DestroyFile ( resultTable ) < 0 )
		{
			HF_PrintError ( "error in deleting temp table hf" );
			return UTE_errno = UTE_HFERROR;
		}
	}

	return UTE_errno = UTE_OK;
}


/*int DM_insert(int argc, char* argv[])

    argv[0]="insert"

    argv[1]=όνομα-σχέσης

    argv[2]=όνομα-πεδίου-1

    argv[3]=τιμή-1

    argv[4]=όνομα-πεδίου-2

    argv[5]=τιμή-2

    .

    .

    .

    argv[argc]=NULL



 *Η συνάρτηση αυτή καλείται από την yyparse όταν ο χρήστης πληκτρολογήσει 
 *μια εντολή INSERT. Για την υλοποίησή της θα πρέπει να χρησιμοποιήσετε τις
 * συναρτήσεις AM_InsertEntry και ΗF_InsertRec.
 */

int DM_insert(int argc, char *argv[])
{
	int fd;
	relDesc reldesc;
	attrDesc *attrs;
	char * record ;
	int i,j, recId;
	int indexes;
	char am_name[MAXNAME + 1];

	if ( ( UTE_errno = SCM_insert(argc, argv)) < 0 ) 
	{
		return UTE_errno;
	}

	if(( UTE_errno = CFM_Lookup(argv[1], &reldesc, &attrs) ) < 0 )
	{ 
		return UTE_errno ;
	}
	/*anoigw to arxeio me onoma to onoma sxeshs */
	if(( fd = HF_OpenFile(argv[1]) ) < 0 )
	{
		HF_PrintError("error in DM_Insert");
		return UTE_errno = UTE_HF_ERROR;
	}


	record = malloc(reldesc.relwidth);
	
	//ftiaksimo tis egrafis pou tha eisagoume
	for( i = 2; i < argc; i+=2)
	{		//gia kathe attribute
		for(j = 0; j < reldesc.attrcnt; j++)
		{
			if(! strcmp(attrs[j].attrname, argv[i]))
			{
				break;
			}
		}
		//to bazoume me to katalilo offset sto record
		memcpy( record + attrs[j].offset, argv[i + 1], attrs[j].attrlength);
	}
	
	//eisagwgi tou record sto arxei
	if(( recId = HF_InsertRec(fd, record, reldesc.relwidth)) < 0 )
	{
		HF_PrintError("error in DM_Insert");
		return UTE_errno = UTE_HF_ERROR;
	}
	
	if(( UTE_errno = HF_CloseFile(fd) ) < 0 )
	{
		HF_PrintError("error in DM_Insert");
		return UTE_HF_ERROR;
	}

	//eisagwgh twn egrafwn sta euretiria

		/*psaxnei na bre pio pedio einai euretiriasmeno */
	for(i = 0; i < reldesc.attrcnt; i++)
	{
		if( attrs[i].indexed )
		{
			//anoigma tou eurethriou
			if( ( indexes = AM_OpenIndex(argv[1], attrs[i].indexno ) ) < 0 )
			{
				AM_PrintError("Error in DM Insert\n");
				return UTE_errno = indexes;
			}

			/*briskei to onoma tou euretiriasmenou pediou sta stoixeia pou mas exoun dwthei */
			for(j = 2; j < argc; j+=2)
			{
				if( !strcmp( attrs[i].attrname , argv[j] ) )
				{/*molis to brei */
					break;
				}
			}
			
			//eisagwgi sto euretirio

			if((UTE_errno = AM_InsertEntry(indexes, attrs[i].attrtype, attrs[i].attrlength, argv[j+1], recId)) < 0 )
			{
				AM_PrintError ("error in DM Insert'n");
				return UTE_errno;
			}
			
			//klisimo tou euretiriou
			if(( UTE_errno = AM_CloseIndex(indexes)) < 0 )
			{
				return UTE_errno;
			}
		}
	}
	//h CFM_Lookup desmeuei xoro alla den ton apodesmeuei
	free(attrs);
	return UTE_OK;
	
}





/* Join Functions */
/* Η ρουτίνα που εκτελεί τον αλγόριθμο των εμφωλιασμένων βρόχων 
 * όταν κανένα επιλεγμένο πεδίο δεν είναι ευρετηριασμένο.
 */
static int NoIndexedJoin ( char *resultTable, int relA_Fd, int relB_Fd, relDesc relDesc_A, relDesc relDesc_B, attrDesc *attrsA, attrDesc *attrsB, char *joinAttributeA, int operator, char *joinAttributeB, char *argv[], int argc, int attributeCount );

/* Η ρουτίνα που εκτελεί τον αλγόριθμο των εμφωλιασμένων βρόχων 
 * όταν ένα επιλεγμένο πεδίο δεν είναι ευρετηριασμένο.
 *Στον εσωτερικό βρόχο μπαίνει το πεδίο της σχέσηςB.
 */

static int OneIndexedJoin ( char *resultTable, int relA_Fd, int relB_Fd, relDesc relDesc_A, relDesc relDesc_B, attrDesc *attrsA, attrDesc *attrsB, char *joinAttributeA, int operator, char *joinAttributeB, char *argv[], int argc, int attributeCount );

/*Η συνάρτηση αυτή καλείται από την yyparse όταν ο χρήστης πληκτρολογήσει 
 *μια εντολή SELECT η οποία είναι τύπου ζεύξης. Για την υλοποίηση της συνάρτησης 
 *αυτής ισχύουν οι ίδιες παρατηρήσεις που δίνονται και για την συνάρτηση DM_select. 
 *Επιπλέον, για τη ζεύξη θα πρέπει να χρησιμοποιηθεί ο αλγόριθμος εμφωλιασμένων βρόχων.
 *Αν υπάρχει ευρετήριο σε κάποιο από τα γνωρίσματα ζεύξης θα πρέπει επίσης υποχρεωτικά 
 *να χρησιμοποιηθεί εφόσον ο τελεστής υποστηρίζεται από τον τύπο του ευρετηρίου.

 argv[0]="join"

    argv[1]=όνομα-σχέσης-αποτελέσματος 

    argv[2]=πλήθος-γνωρισμάτων-τα-οποία-προβάλλονται 

    argv[3]=όνομα-προβαλλόμενης-σχέσης-1

    argv[4]=όνομα-προβαλλόμενου-πεδίου-1

    .

    .

    .

    argv[argc-7]=όνομα-προβαλλόμενης-σχέσης-Ν

    argv[argc-6]=όνομα-προβαλλόμενου-πεδίου-Ν

    argv[argc-5]=όνομα-σχέσης-ζεύξης-1

    argv[argc-4]=όνομα-πεδίου-ζεύξης-1

    argv[argc-3]=τελεστής

    argv[argc-2]=όνομα-σχέσης-ζεύξης-2

    argv[argc-1]=όνομα-πεδίου-ζεύξης-2

    argv[argc]=NULL
*/

int DM_join(int argc, char* argv[])
{
	int optional = 0, attributeCount, relA_Fd, relB_Fd;
	int i, j, createArgc, attrsCopied;
	char resultTable[MAXNAME], relationA[MAXNAME], relationB[MAXNAME];
	char *record_A, *record_B, *resultRecord, **createArgv;
	relDesc relDesc_A, relDesc_B;
	attrDesc *attrsA, *attrsB;

	if ( SCM_join ( argc, argv ) < 0 )
	{
		return UTE_errno = SCM_JOIN;
	}

	/* Αν έχουμε όνομα σχέσης αποτελέσματος, το αποθηκεύουμε */

	if ( argc % 2 == 0 )
	{
		optional = 1;
		strcpy ( resultTable, argv[1] );
	}
	else
	{
		optional = 0;
		strcpy ( resultTable, "KAKA" );		
	}

	/* Φυλάμε τα ονόματα των δύο σχέσεων που εμπλέκονται. */

	strcpy ( relationA, argv[argc - 5] );
	strcpy ( relationB, argv[argc - 2] );

	/* Αριθμός προβαλλόμενων πεδίων. */

	attributeCount = atoi ( argv[1] + optional );

	/* Ανοίγω τη σχέση-ζεύξης A. */

	if ( ( relA_Fd = HF_OpenFile ( relationA ) ) < 0)
	{
		HF_PrintError ( "Error in opening relalionA file" );
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Ανοίγω τη σχέση-ζεύξης B. */

	if ( ( relB_Fd = HF_OpenFile ( relationB ) ) < 0)
	{
		HF_PrintError ( "Error in opening relalionB file" );
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Προκόμηση των πληροφοριών των δύο σχέσεων. */
	
	if ( CFM_Lookup ( relationA, &relDesc_A, &attrsA ) < 0 )
	{
		return UTE_errno = UTE_JOIN;	
	}

	if ( CFM_Lookup ( relationB, &relDesc_B, &attrsB ) < 0 )
	{
		return UTE_errno = UTE_JOIN;	
	}

	/* Δημιουργία του κατάλληλου argument vector ώστε να δημιουργήσουμε την 
	 *( ίσως ) προσωρινή σχέση στους καταλάγους της βάσης.
	 */

	createArgc = attributeCount * 2 + 2;
	createArgv = malloc ( sizeof(char*) * createArgc);
	for ( i = 0; i <= createArgc; i++ )
		createArgv[i] = malloc ( sizeof(char) * MAXNAME );

	strcpy ( createArgv[0], "create" );
	strcpy ( createArgv[1], resultTable );

	/* Αντιγραφή στον argument vector της UT_create τα προβαλόμενα πεδία 
	 *και του τύπου τους.
	 */

	for ( i = 2, j = 2, attrsCopied = 0; attrsCopied < attributeCount; i++ )
	{
		if ( strcmp ( argv[i], relationA ) == 0 )
			continue;
		if ( strcmp ( argv[i], relationB ) == 0 )
			continue;
		if ( atoi ( argv[i] ) == attributeCount )
			continue;
		if ( strcmp ( resultTable, argv[i] ) == 0 )
			continue;

		strcpy ( createArgv[j], argv[i] );
		if ( strcmp ( argv[i - 1], relationA ) == 0 )
		{
			strcpy ( createArgv[j + 1], GetType ( attrsA, argv[i] ) );
			j += 2;
			attrsCopied++;
		}
		else if ( strcmp ( argv[i - 1], relationB )  == 0 )
		{
			strcpy ( createArgv[j + 1], GetType ( attrsB, argv[i] ) );		
			j += 2;
			attrsCopied++;
		}
	}

	strcpy ( createArgv[createArgc - 1], "NULL" );

	for ( i = 0; i < createArgc; i++ )
		printf("%s\n", createArgv[i]);

	/* Δημιουργία της ( ίσως ) προσωρινής σχέσης. */

	if ( UT_create ( createArgc, createArgv ) < 0 )
	{
		return UTE_errno = UTE_CREATE;
	}

	/* Περίπτωση 1: Αν ένα απο τα δύο πεδία είναι ευρετηριασμένα. */

	if ( IsIndexed ( attrsA, argv[argc - 4] ) == TRUE
		 && IsIndexed ( attrsB, argv[argc - 1] ) == FALSE )
	{
		return OneIndexedJoin ( resultTable, relB_Fd, relA_Fd, relDesc_B, relDesc_A, attrsB, attrsA, argv[argc - 1], ToOperator ( argv[argc - 3]), argv[argc - 4], argv, argc, attributeCount );
	}
	else if ( IsIndexed ( attrsA, argv[argc - 4] ) == TRUE
		 && IsIndexed ( attrsB, argv[argc - 1] ) == FALSE )
	{
		return OneIndexedJoin ( resultTable, relA_Fd, relB_Fd, relDesc_A, relDesc_B, attrsA, attrsB, argv[argc - 4], ToOperator ( argv[argc - 3]), argv[argc - 1], argv, argc, attributeCount );
	}

	/* Περίπτωση 2: Αν κανένα απο τα δύο είναι ευρετηριασμένα. */

	if ( IsIndexed ( attrsA, argv[argc - 4] ) == FALSE
		 && IsIndexed ( attrsB, argv[argc - 1] ) == FALSE )
	{
		return NoIndexedJoin ( resultTable, relB_Fd, relA_Fd, relDesc_B, relDesc_A, attrsB, attrsA, argv[argc - 1], ToOperator ( argv[argc - 3]), argv[argc - 4], argv, argc, attributeCount );
	}

	/* Περίπτωση 3: Αν και τα δύο είναι ευρετηριασμένα. */

	if ( IsIndexed ( attrsA, argv[argc - 4] ) == TRUE
		 && IsIndexed ( attrsB, argv[argc - 1] ) == TRUE )
	{
		return OneIndexedJoin ( resultTable, relB_Fd, relA_Fd, relDesc_B, relDesc_A, attrsB, attrsA, argv[argc - 1], ToOperator ( argv[argc - 3]), argv[argc - 4], argv, argc, attributeCount );
	}

}

static int OneIndexedJoin ( char *resultTable, int relA_Fd, int relB_Fd, relDesc relDesc_A, relDesc relDesc_B, attrDesc *attrsA, attrDesc *attrsB, char *joinAttributeA, int operator, char *joinAttributeB, char *argv[], int argc, int attributeCount )
{
	int scanDesc, retval, resultFd, resultRecSize, indexScan, recId;
	char *recordA, *recordB, *resultRecord;
	relDesc resultTableRel;
	attrDesc attributeA, attributeB, *resultTableAttrs;

	recordA = malloc ( sizeof(char) * relDesc_A.relwidth );
	recordB = malloc ( sizeof(char) * relDesc_B.relwidth );

	/* 'Ανοιγμα του αρχείου που θα βάλουμε τις εγγραφές-αποτελέσματα. */

	if ( ( resultFd = HF_OpenFile ( resultTable ) ) < 0 )
	{
		HF_PrintError ( "Error in opening result HF" );
		return UTE_errno = UTE_HF_ERROR;
	}

	/* 'Ανοιγμα του ευρετηρίου του ευρετηριασμένου πεδίου. */

	if ( ( indexScan = AM_OpenIndex ( relDesc_B.relname, GetAttributeInfo ( attrsB, joinAttributeB).indexno) ) < 0 )
	{
		AM_PrintError ( "Error in opening index scan in one-indexed-join" );
		return UTE_errno = UTE_AMERROR;
	}

	/* Προσκόμοιση των πληροφοριών για την σχέση-αποτέλεσμα. */

	if ( CFM_Lookup ( resultTable, &resultTableRel, &resultTableAttrs ) < 0 )
	{
		return UTE_errno = UTE_JOIN;
	}
	resultRecord = malloc ( sizeof(char) * resultTableRel.relwidth );

	/* 'Ανοιγμα scan για να φέρουμε όλες τις εγγραφές της πρώτης σχέσης
	 *μια-μια για να ανοίξουμε στη συνέχεια scan με τιμή την τιμή του πεδίου
	 *της ΄πρώτης σχέσης στη δεύτερη σχέση.
	 */
	
	attributeA = GetAttributeInfo ( attrsA, joinAttributeA );
	attributeB = GetAttributeInfo ( attrsB, joinAttributeB );

	if ( ( scanDesc = HF_OpenFileScan ( relA_Fd, relDesc_A.relwidth, attributeA.attrtype, attributeA.attrlength, attributeA.offset, operator, NULL ) ) < 0 )
	{
		HF_PrintError ( "error in opening external scan in one indexed join" );
		return UTE_errno = UTE_HF_ERROR;
	}

	while ( ( retval = HF_FindNextRec ( scanDesc, recordA ) ) != HFE_EOF )
	{	
		char value[MAXNAME];
		int scanDescB, offset, lenght;

		if ( retval < 0 )
		{
			continue;
		}

		/* Προσκόμοιηση του offset του επιλεγμένου πεδίου απο την εγγραφή της σχέσης A. */

		offset = GetOffset ( attrsA, joinAttributeA );
		lenght = GetAttributeInfo ( attrsA, joinAttributeA ).attrlength;

		/* Πέρασμα της τιμής του επιλεγμένου πεδίου σε έναν πίνακα για να τον δώσουμε στο scan. */

		memcpy ( value, &recordA [ offset ], lenght );

		/* Άνοιγμα scan στο πεδίο της δεύτερης σχέσης με τιμή την τιμή
		 *την τιμή του πεδίου που έχει επιλέξει ο χρήστης απο την πρώτη σχέση.
		 */

		if ( ( scanDescB = AM_OpenIndexScan (  indexScan, attributeB.attrtype, attributeB.attrlength, operator, value ) ) < 0 )
		{
			AM_PrintError ( "Error in no indexed join when opening inner index-scan" );
			return UTE_HF_ERROR;
		}

		while ( ( recId = AM_FindNextEntry ( scanDescB ) ) != AME_EOF )
		{
			int i, j;

			if ( recId < 0 )
			{
				AM_PrintError ( "Error in inner FindNextRec" );
continue;//				return UTE_errno = UTE_AMERROR;
			}
			
			if ( HF_GetThisRec ( relB_Fd, recId, recordB, relDesc_B.relwidth ) < 0 )
			{
				HF_PrintError ( "Error in record fetching in One-Indexed_Join" );
				return UTE_HF_ERROR;
			}

			/* Επιλογή των attributes που έχει ζητήσει ο χρήστης. */

			for ( i = 1, j = 0; j < resultTableRel.attrcnt; i++ )
			{
				attrDesc attributeInfo;
				
				/* Σαρώνω τον argv, αν πέσω στον όνομα σχέσης-αποτελέσματος
				 *ή τα ονόματα των δύο σχέσεων, τα παραλέιπω. 
				 */

				if ( strcmp ( argv[i] , resultTable ) == 0 )
					continue;
				else if ( strcmp ( argv[i], relDesc_A.relname ) == 0 )
					continue;
				else if ( strcmp ( argv[i], relDesc_B.relname ) == 0 )
					continue;
				else if ( atoi ( argv[i] ) == attributeCount )
					continue;
	
				/*Αν βρώ attribute, πέρνω την πληροφορία του απο
				 *τον κατάλληλο πίνακα attrs
				 */
				
				if ( strcmp ( argv[i - 1], relDesc_A.relname ) == 0 )
				{
					/* Αν ανήκει στην σχέση A */

					attributeInfo = GetAttributeInfo ( attrsA, argv[i] );
					memcpy ( &resultRecord[ resultTableAttrs[j].offset ], &recordA[ attributeInfo.offset ], attributeInfo.attrlength );
					j++;
				}
				else if ( strcmp ( argv[i - 1], relDesc_B.relname ) == 0 )
				{
					/* Αν ανήκει στην σχέση B */

					attributeInfo = GetAttributeInfo ( attrsB, argv[i] );
					memcpy ( &resultRecord[ resultTableAttrs[j].offset ], &recordB[ attributeInfo.offset ], attributeInfo.attrlength );
					j++;
				}
				
			}

			/* Εισαγωγή της εγγραφής που χτίσαμε στην καινούρια σχέση. */

			if ( HF_InsertRec ( resultFd, resultRecord, resultTableRel.relwidth ) < 0 )
			{			
				HF_PrintError ( "Error in inserting result records in no indexed join" );
				return UTE_errno = UTE_HF_ERROR;			
			}

		}

		/* Κλείσιμο του index-scan του εσωτερικού βρόγχου. */

		if ( AM_CloseIndexScan ( scanDescB ) )
		{
			HF_PrintError ( "Error in closing inner index-scan loop" );	
			return UTE_errno = UTE_HF_ERROR;
		}

	}

	/* Κλείσιμο του scan του εξωτερικού βρόγχου. */

	if ( HF_CloseFileScan ( scanDesc ) )
	{
		HF_PrintError ( "Error in closing external scan loop" );	
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Κλείσιμο των HF files */

	if ( HF_CloseFile ( relA_Fd ) < 0 )
	{
		HF_PrintError ( "Error in closing external scan loop" );	
		return UTE_errno = UTE_HF_ERROR;	
	}

	if ( HF_CloseFile ( relB_Fd ) < 0 )
	{
		HF_PrintError ( "Error in closing external scan loop" );	
		return UTE_errno = UTE_HF_ERROR;	
	}

	/* Αν ο χρήστης δεν ζήτησε αποθήκευση του αποτελέσματος
	 *σε καινούρια σχέση, τυπώνω τα αποτελέσματα και 
	 *καταστρέφω την προσωρινή σχέση.
	 */

	if ( argc % 2 == 1 )
	{
		char arguments[3][MAXNAME];

		/* Εκτύπωση του αποτελέσματος. */

		strcpy ( arguments[0], "delete" );
		strcpy ( arguments[1], resultTable );
		strcpy ( arguments[2], "NULL" );

		if ( UT_print ( resultTable ) < 0 )
		{
			return UTE_errno = UTE_SELECT;
		}

		if ( UT_destroy ( 3, arguments ) < 0 )
		{
			return UTE_errno = UTE_JOIN;
		}

		if ( HF_DestroyFile ( resultTable ) < 0 )
		{
			HF_PrintError ( "error in deleting temp table hf" );
			return UTE_errno = UTE_HFERROR;
		}

	}

	free ( attrsA );
	free ( attrsB );
	return UTE_OK;
}

static int NoIndexedJoin ( char *resultTable, int relA_Fd, int relB_Fd, relDesc relDesc_A, relDesc relDesc_B, attrDesc *attrsA, attrDesc *attrsB, char *joinAttributeA, int operator, char *joinAttributeB, char *argv[], int argc, int attributeCount )
{
	int scanDesc, retval, resultFd, resultRecSize;
	char *recordA, *recordB, *resultRecord;
	relDesc resultTableRel;
	attrDesc attributeA, attributeB, *resultTableAttrs;

	recordA = malloc ( sizeof(char) * relDesc_A.relwidth );
	recordB = malloc ( sizeof(char) * relDesc_B.relwidth );

	/* 'Ανοιγμα του αρχείου που θα βάλουμε τις εγγραφές-αποτελέσματα. */

	if ( ( resultFd = HF_OpenFile ( resultTable ) ) < 0 )
	{
		HF_PrintError ( "Error in opening result HF" );
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Προσκόμοιση των πληροφοριών για την σχέση-αποτέλεσμα. */

	if ( CFM_Lookup ( resultTable, &resultTableRel, &resultTableAttrs ) < 0 )
	{
		return UTE_errno = UTE_JOIN;
	}
	resultRecord = malloc ( sizeof(char) * resultTableRel.relwidth );

	/* 'Ανοιγμα scan για να φέρουμε όλες τις εγγραφές της πρώτης σχέσης
	 *μια-μια για να ανοίξουμε στη συνέχεια scan με τιμή την τιμή του πεδίου
	 *της ΄πρώτης σχέσης στη δεύτερη σχέση.
	 */
	
	attributeA = GetAttributeInfo ( attrsA, joinAttributeA );
	attributeB = GetAttributeInfo ( attrsB, joinAttributeB );

	if ( ( scanDesc = HF_OpenFileScan ( relA_Fd, relDesc_A.relwidth, attributeA.attrtype, attributeA.attrlength, attributeA.offset, operator, NULL ) ) < 0 )
	{
		return UTE_errno = UTE_HF_ERROR;
	}

	while ( ( retval = HF_FindNextRec ( scanDesc, recordA ) ) != HFE_EOF )
	{	
		char value[MAXNAME];
		int scanDescB, offset, lenght;

		if ( retval < 0 )
		{
			continue;
		}

		/* Προσκόμοιηση του offset του επιλεγμένου πεδίου απο την εγγραφή της σχέσης A. */

		offset = GetOffset ( attrsA, joinAttributeA );
		lenght = GetAttributeInfo ( attrsA, joinAttributeA ).attrlength;

		/* Πέρασμα της τιμής του επιλεγμένου πεδίου σε έναν πίνακα για να τον δώσουμε στο scan. */

		memcpy ( value, &recordA [ offset ], lenght );

		/* Άνοιγμα index-scan στο πεδίο της δεύτερης σχέσης με τιμή την τιμή
		 *την τιμή του πεδίου που έχει επιλέξει ο χρήστης απο την πρώτη σχέση.
		 */

		if ( ( scanDescB = HF_OpenFileScan ( relB_Fd, relDesc_B.relwidth, attributeB.attrtype, attributeB.attrlength, attributeB.offset, operator, value ) ) < 0 )
		{
			HF_PrintError ( "Error in no indexed join when opening inner scan" );
			return UTE_HF_ERROR;
		}

		while ( HF_FindNextRec ( scanDescB, recordB ) != HFE_EOF )
		{
			int i, j;

			if ( retval < 0 )
			{
				continue;
			}
			
			/* Επιλογή των attributes που έχει ζητήσει ο χρήστης. */

			for ( i = 1, j = 0; j < resultTableRel.attrcnt; i++ )
			{
				attrDesc attributeInfo;
				
				/* Σαρώνω τον argv, αν πέσω στον όνομα σχέσης-αποτελέσματος
				 *ή τα ονόματα των δύο σχέσεων, τα παραλέιπω. 
				 */

				if ( strcmp ( argv[i] , resultTable ) == 0 )
					continue;
				else if ( strcmp ( argv[i], relDesc_A.relname ) == 0 )
					continue;
				else if ( strcmp ( argv[i], relDesc_B.relname ) == 0 )
					continue;
				else if ( atoi ( argv[i] ) == attributeCount )
					continue;
	
				/*Αν βρώ attribute, πέρνω την πληροφορία του απο
				 *τον κατάλληλο πίνακα attrs
				 */
				
				if ( strcmp ( argv[i - 1], relDesc_A.relname ) == 0 )
				{
					/* Αν ανήκει στην σχέση A */

					attributeInfo = GetAttributeInfo ( attrsA, argv[i] );
					memcpy ( &resultRecord[ resultTableAttrs[j].offset ], &recordA[ attributeInfo.offset ], attributeInfo.attrlength );
					j++;
				}
				else if ( strcmp ( argv[i - 1], relDesc_B.relname ) == 0 )
				{
					/* Αν ανήκει στην σχέση B */

					attributeInfo = GetAttributeInfo ( attrsB, argv[i] );
					memcpy ( &resultRecord[ resultTableAttrs[j].offset ], &recordB[ attributeInfo.offset ], attributeInfo.attrlength );
					j++;
				}
				
			}

			/* Εισαγωγή της εγγραφής που χτίσαμε στην καινούρια σχέση. */

			if ( HF_InsertRec ( resultFd, resultRecord, resultTableRel.relwidth ) < 0 )
			{			
				HF_PrintError ( "Error in inserting result records in no indexed join" );
				return UTE_errno = UTE_HF_ERROR;			
			}

		}

		if ( HF_CloseFileScan ( scanDescB ) )
		{
			HF_PrintError ( "Error in closing inner scan loop" );	
			return UTE_errno = UTE_HF_ERROR;
		}

	}

	if ( HF_CloseFileScan ( scanDesc ) )
	{
		HF_PrintError ( "Error in closing external scan loop" );	
		return UTE_errno = UTE_HF_ERROR;
	}

	/* Κλείσιμο των HF files */

	if ( HF_CloseFile ( relA_Fd ) < 0 )
	{
		HF_PrintError ( "Error in closing external scan loop" );	
		return UTE_errno = UTE_HF_ERROR;	
	}

	if ( HF_CloseFile ( relB_Fd ) < 0 )
	{
		HF_PrintError ( "Error in closing external scan loop" );	
		return UTE_errno = UTE_HF_ERROR;	
	}

	/* Αν ο χρήστης δεν ζήτησε αποθήκευση του αποτελέσματο
	 *σε καινούρια σχέση, τυπώνω τα αποτελέσματα και 
	 *καταστρέφω την προσωρινή σχέση.
	 */

	if ( argc % 2 == 1 )
	{
		char arguments[3][MAXNAME];

		/* Εκτύπωση του αποτελέσματος. */

		strcpy ( arguments[0], "delete" );
		strcpy ( arguments[1], resultTable );
		strcpy ( arguments[2], "NULL" );

		if ( UT_print ( resultTable ) < 0 )
		{
			return UTE_errno = UTE_SELECT;
		}

		if ( UT_destroy ( 3, arguments ) < 0 )
		{
			return UTE_errno = UTE_JOIN;
		}

		if ( HF_DestroyFile ( resultTable ) < 0 )
		{
			HF_PrintError ( "error in deleting temp table hf" );
			return UTE_errno = UTE_HFERROR;
		}

	}

	free ( attrsA );
	free ( attrsB );
	return UTE_OK;
}

/*int DM_delete(int argc, char* argv[])

    argv[0]="delete"

    argv[1]=όνομα-σχέσης

    argv[argc-3]=όνομα-πεδίου 

    argv[argc-2]=τελεστής 

    argv[argc-1]=τιμή 

    argv[argc]=NULL



Η συνάρτηση αυτή καλείται από την yyparse όταν ο χρήστης πληκτρολογήσει
μια εντολή DELETE. Για την υλοποίησή της θα πρέπει να χρησιμοποιήσετε τις 
συναρτήσεις AM_DeleteEntry και ΗF_DeleteRec. Αν υπάρχει ευρετήριο στο γνώρισμα
που χρησιμοποιείται για την επιλογή των εγγραφών θα πρέπει υποχρεωτικά να χρησιμοποιηθεί
εφόσον ο τελεστής υποστηρίζεται από τον τύπο του ευρετηρίου.
*/

int DM_delete(int argc, char* argv[])
{
	int j, i, fd, scandesc, recId, *indexes, op; 
	char am_name[MAXNAME + 1];
	char * record, *rec ;
	relDesc reldesc;
	attrDesc *attrs;

	
	if(( UTE_errno = SCM_Delete(argc, argv)) < 0 )  // elegxos orismatwn
	{
		return UTE_errno;
	}
	
	if(( UTE_errno = CFM_Lookup(argv[1], &reldesc, &attrs) ) < 0 )  // pairnoyme ta stoixeia ths sxeshs apo toy pinakes attrcat k relcat
	{
		return UTE_errno ;
	}

	indexes=malloc( reldesc.attrcnt * sizeof(int) );   // sto indexes apo8hkeyoyme ta filedescs twn eyrethriwn

	if ( argc == 5 ){      // an exoyme syn8hkh

		for(j = 0; j < reldesc.attrcnt; j++)    // briskoyme ston pinaka attrs to pedio ths syn8hkhs
		{
			if(! strcmp(attrs[j].attrname, argv[2]))
			{
				break;
			}
		}
		
		if ( attrs[j].indexed ) {  // an exei eyrethrio


			for (i=0 ; i < reldesc.attrcnt; i++)	// anoigoyme ola ta eyrethria olwn twn pediwn ths sxeshs		
			{
				if ( attrs[i].indexed )
				{
					//anoigma tou eurethriou
					if( (indexes[i] = AM_OpenIndex(attrs[j].attrname, attrs[i].indexno)) < 0 )
					{
						return UTE_errno = indexes[i];
					}
				}
			}

			op=find_operator(argv[3]);  // briskoyme poios operator einai to argv[3]
///////////////////////////////////////// ? ////////////////////////////
			// anoigoyme sarwsh
			if ( (scandesc = AM_OpenIndexScan(indexes[j], attrs[j].attrtype, attrs[j].attrlength, op, argv[4])) < 0 ) 
			{
				return UTE_errno = scandesc;
			}
			// anoigma arxeioy
			if(( fd = HF_OpenFile(argv[1]) ) < 0 )
			{
				HF_PrintError("error in DM_Delete");
				return UTE_errno = UTE_HF_ERROR;
			}

			record = malloc(reldesc.relwidth); 

			while ( (recId=AM_FindNextEntry(scandesc)) >=0 )
			{
				// gia na paroyme to record
				if ( (UTE_errno=HF_GetThisRec(fd, recId, record, reldesc.relwidth)) < 0 )
				{
					HF_PrintError("error in DM_Delete");
					return UTE_errno = UTE_HF_ERROR;
				}
				// diagrafh eggrafhs
				if ( (UTE_errno=HF_DeleteRec(fd, recId, reldesc.relwidth)) < 0 )
				{
					HF_PrintError("error in DM_Delete");
					return UTE_errno = UTE_HF_ERROR;
				}

				for (i=0 ; i < reldesc.attrcnt; i++)
				{
					if ( attrs[i].indexed )   // an to pedio exei eyerthrio, diagrafoyme k apo to eyrethrio
					{
						rec=record+attrs[i].offset;   // bazw to rec na deixnei sthn timh poy 8eloyme

						if ( (UTE_errno=AM_DeleteEntry(indexes[i], attrs[i].attrtype, attrs[i].attrlength, rec, recId)) < 0 )
						{
							return UTE_errno;
						}
					}
				}
			}

			free(record);

			// kleisimo eyrethiwn
			for (i=0 ; i < reldesc.attrcnt; i++)
			{
				if ( attrs[i].indexed )
				{
					if(( UTE_errno = AM_CloseIndex(indexes[i])) < 0 )
					{
						return UTE_errno;
					}
				}
			}	
			// kleisimo sarwshs
			if(( UTE_errno = AM_CloseIndexScan(scandesc)) < 0 )
			{
				return UTE_errno;
			}
			// kleisimo arxeioy
			if(( UTE_errno = HF_CloseFile(fd) ) < 0 )
			{
				HF_PrintError("error in DM_Insert");
				return UTE_errno=UTE_HF_ERROR;
			}
		}
		else                  // an den exei eyrethrio
		{
			// anoigma arxioy
			if(( fd = HF_OpenFile(argv[1]) ) < 0 )
			{
				HF_PrintError("error in DM_Delete");
				return UTE_errno = UTE_HF_ERROR;
			}

			op=find_operator(argv[3]); // briskoyme ton operator toy argv[3]
			// anoigm sarwshs
			if ( (scandesc = HF_OpenFileScan(fd,reldesc.relwidth, attrs[j].attrtype, attrs[j].attrlength, attrs[j].offset, op, argv[4])) < 0 )
			{
				HF_PrintError("error in DM_Delete");
				return UTE_errno = UTE_HF_ERROR;
			}

			for (i=0 ; i < reldesc.attrcnt; i++)	// anoigoyme ola ta eyrethria olwn twn pediwn ths sxeshs		
			{
				if ( attrs[i].indexed )
				{
					//anoigma tou eurethriou
					if( (indexes[i] = AM_OpenIndex(attrs[i].attrname, attrs[i].indexno)) < 0 )
					{
						return UTE_errno = indexes[i];
					}
				}
			}

			record = malloc(reldesc.relwidth); 
			// briskoyme oles tis eggrafes poy throyn th syn8hkh
			while ( (recId=HF_FindNextRec(scandesc, record)) >=0 )
			{
				// diagrafh eggrafhs
				if ( (UTE_errno=HF_DeleteRec(fd, recId, reldesc.relwidth)) < 0 )
				{
					HF_PrintError("error in DM_Delete");
					return UTE_errno = UTE_HF_ERROR;
				}

				for (i=0 ; i < reldesc.attrcnt; i++)
				{
					if ( attrs[i].indexed )  // gia ta pedia poy exoyn eyrethrio
					{
						rec=record+attrs[i].offset;   // bazw to rec na deixnei sthn timh poy 8eloyme

						if ( (UTE_errno=AM_DeleteEntry(indexes[i], attrs[i].attrtype, attrs[i].attrlength, rec, recId)) < 0 )
						{
							return UTE_errno;
						}
					}
				}
			}

			free(record);
			// kleisimo sarwshs
			if(( UTE_errno = HF_CloseFileScan(scandesc) ) < 0 )
			{
				HF_PrintError("error in DM_Delete");
				return UTE_errno=UTE_HF_ERROR;
			}
			// kleismo arxeioy
			if(( UTE_errno = HF_CloseFile(fd) ) < 0 )
			{
				HF_PrintError("error in DM_Delete");
				return UTE_errno=UTE_HF_ERROR;
			}
			// kleisimo eyrethriwn
			for (i=0 ; i < reldesc.attrcnt; i++)
			{
				if ( attrs[i].indexed )
				{
					if(( UTE_errno = AM_CloseIndex(indexes[i])) < 0 )
					{
						return UTE_errno;
					}
				}
			}	
		}
	}
	else      // an den yparxei syn8hkh
	{

		//katastrofh toy arxeioy ( afoy 8eloyme na diagrapsoyme oles tis eggrafes poy exei
		if ( HF_DestroyFile ( argv[1]) < 0 )
		{
			HF_PrintError ( "Error in DM_delete" );
			return UTE_errno  = UTE_HFERROR;
		}
		// k ksanadhmioyrgia gia na yparxei k apla na einai keno
		if ( HF_CreateFile ( argv[1]) < 0 )
		{
			HF_PrintError ( "Error in DM_delete" );
			return UTE_errno  = UTE_HFERROR;
		}

		// omoiws katastrofh k ksanadhmioygia twn eyrethriwn twn pediwn
		for (i=0 ; i < reldesc.attrcnt; i++)
		{
			if ( attrs[i].indexed )
			{
				if ( (UTE_errno=AM_DestroyIndex(attrs[i].attrname, attrs[i].indexno)) < 0)
				{
					return UTE_errno;
				}
					
				if ( (UTE_errno=AM_CreateIndex(attrs[i].attrname, attrs[i].indexno, attrs[i].attrtype, attrs[i].attrlength)) < 0)
				{
					return UTE_errno;
				}
			}
		}				
	}

	free(attrs);
	return UTE_errno=UTE_OK;

}



/* UTILITIES */	
static char *GetType ( attrDesc *attrs, char *attrName )
{
	int i;
	char *type;
	type = malloc ( sizeof(char) * 7 );

	for ( i = 0; ; i++ )
	{
		if ( strcmp ( attrs[i].attrname, attrName ) == 0 )
		{
			if ( attrs[i].attrtype == 'i' || attrs[i].attrtype == 'f' )
			{
				sprintf( type, "'%c'", attrs[i].attrtype);
			}
			else
			{
				sprintf ( type, "'%c%d'", attrs[i].attrtype, attrs[i].attrlength );
			}

			return type;
		}
	}
}
static int GetLenght ( char *type )
{
	if ( type[0] == 'i' || type[0] == 'f')
	{
		return 4;
	}
	else
	{
		return atoi ( ++type );
	}
}
static int GetOffset ( attrDesc *attrs, char *attribute)
{
	int i;

	for ( i = 0;; i++ )
	{
		if ( strcmp ( attrs[i].attrname, attribute ) == 0 )
			return attrs[i].offset;
	}
}


static attrDesc GetAttributeInfo ( attrDesc *attrs, char *attribute )
{
	int i;

	for ( i = 0 ;; i++ )
	{
		if ( strcmp ( attrs[i].attrname, attribute ) == 0 )
			return attrs[i];
	}
}


static int ToOperator ( char *op )
{
	if ( strcmp ( op, "=" ) == 0 )
	{
		return EQUAL;
	}
	if ( strcmp ( op, "<" ) == 0 )
	{
		return LESS_THAN;
	}
	if ( strcmp ( op, ">" ) == 0 )
	{
		return GREATER_THAN;
	}
	if ( strcmp ( op, "<=" ) == 0 )
	{
		return LESS_THAN_OR_EQUAL;
	}
	if ( strcmp ( op, ">=" ) == 0 )
	{
		return GREATER_THAN_OR_EQUAL;
	}
	if ( strcmp ( op, "!=" ) == 0 )
	{
		return NOT_EQUAL;
	}
}


static BOOLEAN IsIndexed ( attrDesc *attrs, char *attribute )
{
	int i;

	for ( i = 0;; i++ )
	{
		if ( strcmp ( attrs[i].attrname, attribute ) == 0 )
			return attrs[i].indexed;
	}
}

int find_operator(char* op)
{
	if (!strcmp(op, "="))
		return EQUAL;
	else if (!strcmp(op, "<"))
		return LESS_THAN;
	else if (!strcmp(op, ">"))
		return GREATER_THAN;
	else if (!strcmp(op, "<="))
		return LESS_THAN_OR_EQUAL;
	else if (!strcmp(op, ">="))
		return GREATER_THAN_OR_EQUAL;
	else if (!strcmp(op, "!="))
		return NOT_EQUAL;
	else 
		return UTE_errno=UTE_OPERATOR;
}


